#pragma once
/*
 * @Author: 生俊甫 1758142861@qq.com
 * @Date: 2025-01-28 15:38:17
 * @LastEditors: 生俊甫 1758142861@qq.com
 * @LastEditTime: 2025-02-11 15:39:39
 * @FilePath: /sjf/weChat_project/test_to_there/framework/brpc_test/channel.hpp
 * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
 */
#include <iostream>
#include <string>
#include <vector>
#include <memory>
#include <mutex>
#include <thread>
#include <functional>
#include <brpc/channel.h>
#include "logger.hpp"

//单个信道
class ServiceChannel
{
public:
    using ptr= std::shared_ptr<ServiceChannel>;
    using ChannelPtr = std::shared_ptr<brpc::Channel>;
    ServiceChannel(const std::string &name)
        : _service_name(name), _index(0) {}
    void append(const std::string &host) // 服务新增一个节点
    {
        auto channel = std::make_shared<brpc::Channel>();
        brpc::ChannelOptions options;
        options.connect_timeout_ms = -1; // 连接等待超时事件， -1一直等待
        options.timeout_ms = -1;         // rpc等待超时事件 -1一直等待
        options.max_retry = 3;           // 请求重连最大次数
        options.protocol = "baidu_std";  // 使用默认的baidu_std
        // int Init(const char* server_addr_and_port, const ChannelOptions* options);
        int ret = channel->Init(host.c_str(), &options);
        if (ret == -1)
        {
            LOG_ERROR("初始化{}-{}信道失败!",_service_name,host);
            return;
        }
        std::unique_lock<std::mutex> lock(_mutex);
        _hosts.insert(std::make_pair(host,channel));
        _channels.push_back(channel);
    }
    void remove(const std::string &host) // 服务下线一个节点
    {
        std::unique_lock<std::mutex> lock(_mutex);
        auto it = _hosts.find(host);
        if(it == _hosts.end())
        {
            LOG_WARN("{}-{}节点删除信道时,没有找到对应信道信息",_service_name,host);
            return;
        }
        for(auto vit = _channels.begin(); vit != _channels.end(); vit++)
        {
            if(*vit == it->second)
            {
                _channels.erase(vit);
                break;;
            }
        }
        _hosts.erase(it);
    }
    ChannelPtr choose() // 通过轮转获取一个channel
    {
        std::unique_lock<std::mutex> lock(_mutex);
        if(_channels.size() == 0)
        {
            LOG_ERROR("当前没有能够提供{} 服务的节点",_service_name);
            return ChannelPtr();
        }
        int32_t idx = _index++ % _channels.size();
        return _channels[idx];
    }

private:
    std::mutex _mutex;                                  //
    int32_t _index;                                     // 轮转下标计数器
    std::string _service_name;                          // 当前服务器名称
    std::vector<ChannelPtr> _channels;                  // 当前服务器对应的信道集合
    std::unordered_map<std::string, ChannelPtr> _hosts; // 主机地址和信道映射关系
};

//管理ServiceChannel类
class ServiceManager
{
public:
    using ptr = std::shared_ptr<ServiceManager>;
    //获取指定服务的节点信道
    ServiceChannel::ChannelPtr choose(const std::string& service_name)
    {
        std::unique_lock<std::mutex> lock(_mutex);
        auto sit = _services.find(service_name);
        if(sit == _services.end())
        {
            LOG_ERROR("当前没有能够提供{} 服务的节点",service_name);
            return ServiceChannel::ChannelPtr();
        }
        return sit->second->choose();
    }
    //声明，需要关注哪些服务的上下线
    void declared(const std::string& service_name)
    {
        std::unique_lock<std::mutex> lock(_mutex);
        _follow_services.insert(service_name);
    }
    //上线时调用的回调接口,将服务节点管理起来
    void onServiceOnIine(const std::string& service_instance,const std::string host)
    {
        std::string service_name = getServiceName(service_instance); 
        ServiceChannel::ptr service;
        {
            std::unique_lock<std::mutex> lock(_mutex);
            auto fit = _follow_services.find(service_name);
            if(fit == _follow_services.end())
            {
                LOG_DEBUG("{}-{}服务上线了,但是不是关心的对象",service_name,host);
                return ;
            }
            auto sit = _services.find(service_name);
            if(sit == _services.end())
            {
                service = std::make_shared<ServiceChannel>(service_name);
                _services.insert(std::make_pair(service_name,service));
            }
            else { service = sit->second; }            
        }
        if(!service)
        {
            LOG_ERROR("新增{} 服务管理节点失败!",service_name);
            return ;
        }
        service->append(host);
    } 
    //下线时调用的回调接口，从服务节点中对其进行删除 
    void onServiceOffIine(const std::string& service_instance,const std::string host)
    {
        std::string service_name = getServiceName(service_instance); 
        ServiceChannel::ptr service;
        {
            std::unique_lock<std::mutex> lock(_mutex);
            auto fit = _follow_services.find(service_name);
            if(fit == _follow_services.end())
            {
                LOG_DEBUG("{}-{}服务下线了,但是不是关心的对象",service_name,host);
                return ;
            }
            auto sit = _services.find(service_name);
            if(sit == _services.end())
            {
                LOG_WARN("删除{}服务节点时,没有找到管理对象",service_name);
                return ;
            }
            service = sit->second;
        }
        service->remove(host);
    } 
private:
    std::string getServiceName(const std::string& service_name)
    {
        auto pos = service_name.find_last_of('/');
        if(pos == std::string::npos) return service_name;
        return service_name.substr(0,pos);
    }
private:
    std::mutex _mutex;
    std::unordered_set<std::string> _follow_services;
    std::unordered_map<std::string,ServiceChannel::ptr> _services;
};